package com.info.zhiduoduo.common.utils;

import com.google.common.collect.Maps;
import com.google.common.net.InternetDomainName;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class UrlUtil {

	private static final String QUESTION_MARK = "\\?";
	public static final String AND_MARK = "&";
	private static final String EQUAL_MARK = "=";

	/**
	 * 解析url，取url的路径部分。返回"?"前半部分，如果没有"?"，直接返回原url。比如：
	 * <p> https://a.bbbb.com/c/d.html --> https://a.bbbb.com/c/d.html
	 * <p> a.bbbb.com/c/d.html?k1=v1&k2=v2 --> a.bbbb.com/c/d.html
	 * <p> http://a.bbbb.com/c/d --> http://a.bbbb.com/c/d
	 *
	 * @param url 原始url
	 * @return url路径部分
	 */
	public static String parseUrlPath(String url) {
		if (StringUtils.isBlank(url)) return url;
		if (!url.contains("?")) return url;
		return url.split(QUESTION_MARK)[0];
	}

	/**
	 * 解析url，取url的参数部分。返回"?"后半部分，如果没有"?"，返回空字符串。比如：
	 * <p> https://a.bbbb.com/c/d.html --> ""
	 * <p> a.bbbb.com/c/d.html?k1=v1&k2=v2 --> k1=v1&k2=v2
	 * <p> http://a.bbbb.com/c/d --> ""
	 *
	 * @param url 原始url
	 * @return url参数
	 */
	public static String parseUrlParam(String url) {
		if (StringUtils.isBlank(url)) return "";
		if (!url.contains("?")) return "";
		return url.split(QUESTION_MARK)[1];
	}

	/**
	 * 解析带参数的url,返回所有参数键值对
	 *
	 * @param url 比如: xxxx.xxxx.com?k1=v1&k2=v2
	 * @return
	 */
	public static Map<String, String> parseUrlParamPairs(String url) {
		if (StringUtils.isBlank(url)) return Maps.newHashMap();
		String parameterParts;
		if (url.contains("?")) { // contains方法只能手动写？，不能转义
			String[] urlParts = url.split(QUESTION_MARK); // split是匹配正则\\?，需要转义
			parameterParts = urlParts[1];
		} else {
			parameterParts = url;
		}
		return parseParamPairs(parameterParts);
	}

	/**
	 * 从参数串种解析参数键值对
	 *
	 * @param paramStr 只能是参数串的字符串,比如: k1=v1&k2=v2; 如果带有其他符号,会导致解析失败.
	 * @return
	 */
	public static Map<String, String> parseParamPairs(String paramStr) {
		Map<String, String> map = Maps.newHashMap();
		if (StringUtils.isBlank(paramStr)) return map;
		List<String> parameters = StringUtil.splitToStr(paramStr, AND_MARK);
		if (CollectionUtils.isNotEmpty(parameters)) {
			for (String param : parameters) {
				if (param.contains(EQUAL_MARK)) {
					String[] kv = param.split(EQUAL_MARK);
					map.put(kv[0], kv[1]);
				}
			}
		}
		return map;
	}

	/**
	 * 组装url,拼接参数.
	 *
	 * @param domain     null或空则不会拼接域名部分.
	 * @param parameters 参数
	 * @return
	 */
	public static String formUrl(String domain, Map<String, String> parameters) {
		StringBuilder sb = new StringBuilder();
		if (StringUtils.isNotBlank(domain)) {
			sb.append(domain);
		}
		if (MapUtils.isNotEmpty(parameters)) {
			String params = parameters.entrySet()
					.stream()
					.map(entry -> formParamPair(entry.getKey(), entry.getValue()))
					.collect(Collectors.joining(AND_MARK));
			if (domain.contains("?")) sb.append(AND_MARK);
			else sb.append("?");
			sb.append(params);
		}
		return sb.toString();
	}

	public static String formParamPair(String k, String v) {
		return StringUtils.joinWith(EQUAL_MARK, k, v);
	}

	/**
	 * 替换url参数中指定的key的值。
	 * <p> 如果url没有这个key，则直接拼接上这个key
	 *
	 * @param url      原始url或参数字符串。可以是完整的url，比如：http://www.xxx.com/1?k1=v1&k2=v2；也可以是部分url，比如 ?k1=v1&k2=v2 或 k1=v1&k2=v2
	 * @param key      需要被替换值的参数key
	 * @param newValue 新的参数值。
	 * @return 返回新的url，如果替换失败，返回原始的url字符串
	 */
	public static String replaceUrlParamValue(String url, String key, String newValue) {
		return replaceUrlParamValue(url, key, newValue, true);
	}

	/**
	 * 替换url参数中指定的key的值。如果url没有这个key，则直接拼接上这个key
	 *
	 * @param url            原始url或参数字符串。可以是完整的url，比如：http://www.xxx.com/1?k1=v1&k2=v2；也可以是部分url，比如 ?k1=v1&k2=v2 或 k1=v1&k2=v2
	 * @param key            需要被替换值的参数key
	 * @param newValue       新的参数值。
	 * @param addIfNotExists 如果原始url中没有这个key，是否需要直接拼接这个key和对应的newValue
	 * @return 返回新的url，如果替换失败，返回原始的url字符串
	 */
	public static String replaceUrlParamValue(String url, String key, String newValue, boolean addIfNotExists) {
		if (StringUtils.isBlank(url)) url = "";
		// key 不能为空
		if (StringUtils.isBlank(key)) return url;

		Map<String, String> paramPairs = parseUrlParamPairs(url);
		if (paramPairs.containsKey(key)) {
			// 存在这个key
			String oldPair = formParamPair(key, paramPairs.get(key));
			String newPair = formParamPair(key, newValue);
			return url.replace(oldPair, newPair);
		} else if (addIfNotExists) {
			// 不存在，但是可以添加
			String newPair = formParamPair(key, newValue);
			if (StringUtils.isNotBlank(url)) url += AND_MARK;
			url += newPair;
			return url;
		}
		return url;
	}

	/**
	 * 解析域名,去掉http协议和参数部分.
	 *
	 * @param url
	 * @return
	 */
	public static String parseDomainHost(String url) {
		String pattern = "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}";

		Pattern p = Pattern.compile(pattern);
		String line = url;
		Matcher m = p.matcher(line);

		if (m.find()) {
			//匹配结果
			String domain = m.group();

			domain = domain.replace("https", "http");
			domain = domain.substring(7);
			return domain;
		}
		return null;
	}

	/**
	 * 解析出顶级域名,去掉http协议,参数部分和子域名
	 * <p> 如果域名后缀不是共用后缀,则会解析失败, 比如
	 *
	 * @param urlstr 域名url，不能是ip地址
	 * @return
	 */
	public static String parseTopDomainHost(String urlstr) {
		try {
			URL url = new URL(urlstr);
			String host = url.getHost();
			InternetDomainName domainName = InternetDomainName.from(host);
			return domainName.topPrivateDomain().toString();
		} catch (Exception e) {}
		return null;
	}

	/**
	 * 判断是否是IP地址字符串
	 *
	 * @param str
	 * @return
	 */
	public static boolean isIP(String str) {
		String pattern = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";

		Pattern r = Pattern.compile(pattern);
		Matcher m = r.matcher(str);
		return m.matches();
	}

	public static void main(String[] args) {
		String url = "http://abc.kochava.com?click_id={click_id}&adid={adid}&site_id={site_id}";
		Map<String, String> map = parseUrlParamPairs(url);
		System.out.println("map = " + map.toString());

		String newUrl = "http://abc.kochava.com";
		String s = formUrl(newUrl, map);
		System.out.println("s = " + s);

		// String urlstr = "49.232.130.245";
		String urlstr = "http://abc.kochava.com.xx?click_id={click_id}&adid={adid}&site_id={site_id}";
		String domainHost = parseDomainHost(urlstr);
		System.out.println("domainHost = " + domainHost);

		String topDomainHost = parseTopDomainHost(urlstr);
		System.out.println("topDomainHost = " + topDomainHost);

		String newUrl1 = replaceUrlParamValue(url, "site_id", "xxxx");
		System.out.println("newUrl1 = " + newUrl1);
	}
}
